<template>
  <div class="network-graph-container" ref="container">
    <svg
      ref="svg"
      class="network-svg"
      @contextmenu.prevent
      @click="_handleCanvasClick"
    >
      <defs>
        <marker
          id="arrowhead"
          markerWidth="10"
          markerHeight="7"
          refX="8"
          refY="3.5"
          orient="auto"
          markerUnits="strokeWidth"
        >
          <path d="M0,0 L0,7 L8,3.5 z" fill="#999" />
        </marker>

        <marker
          id="arrowhead-highlight"
          markerWidth="10"
          markerHeight="7"
          refX="8"
          refY="3.5"
          orient="auto"
          markerUnits="strokeWidth"
        >
          <path d="M0,0 L0,7 L8,3.5 z" fill="#4a90e2" />
        </marker>

        <!-- 阴影滤镜 -->
        <filter id="drop-shadow" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur in="SourceAlpha" stdDeviation="3" />
          <feOffset dx="0" dy="2" result="offset" />
          <feComponentTransfer>
            <feFuncA type="linear" slope="0.3" />
          </feComponentTransfer>
          <feMerge>
            <feMergeNode />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>
      </defs>

      <g class="zoom-group">
        <g class="links-group"></g>
        <g class="nodes-group"></g>
        <g class="labels-group"></g>
      </g>
    </svg>

    <!-- 右键菜单 -->
    <div
      v-show="contextMenu.visible && isEditor"
      class="context-menu"
      :style="{
        left: contextMenu.x + 'px',
        top: contextMenu.y + 'px',
      }"
      @click.stop
    >
      <div class="menu-item" @click="_handleAddNode">
        <i class="icon-add"></i>
        <span>添加节点</span>
      </div>
      <div class="menu-item" @click="_handleEditNode">
        <i class="icon-edit"></i>
        <span>编辑当前节点</span>
      </div>
      <div class="menu-separator"></div>
      <div class="menu-item danger" @click="_handleDeleteNode">
        <i class="icon-delete"></i>
        <span>删除当前节点</span>
      </div>
    </div>

    <!-- 节点编辑抽屉 -->
    <el-drawer
      v-model="nodeEditDialog.visible"
      :title="nodeEditDialog.isAdd ? '添加节点' : '编辑节点'"
      direction="rtl"
      size="600px"
      :before-close="_handleDrawerClose"
      destroy-on-close
    >
      <div class="drawer-content">
        <div class="drawer-body">
          <!-- 节点基本信息 -->
          <div class="form-section">
            <h4>节点信息</h4>
            <div class="form-row">
              <div class="form-group">
                <label>节点名称 *</label>
                <el-input
                  v-model="nodeEditDialog.form.nodeName"
                  placeholder="请输入节点名称"
                  maxlength="50"
                  show-word-limit
                  clearable
                />
              </div>
              <div class="form-group">
                <label>节点类型 *</label>
                <el-select
                  v-model="nodeEditDialog.form.nodeType"
                  placeholder="请选择节点类型"
                  filterable
                  clearable
                  style="width: 100%"
                >
                  <el-option
                    v-for="(nodeType, index) in nodeTypes"
                    :key="index"
                    :value="nodeType.label || nodeType.name"
                    :label="nodeType.label || nodeType.name"
                  />
                </el-select>
              </div>
            </div>
          </div>

          <!-- 节点关系 -->
          <div class="form-section">
            <div class="section-header">
              <h4>节点关系</h4>
              <button class="btn-add" @click="_addRelation">
                <i class="icon-add"></i>
                添加关系
              </button>
            </div>

            <div
              v-if="nodeEditDialog.form.relations.length === 0"
              class="empty-state"
            >
              暂无关系，点击上方"添加关系"按钮来添加
            </div>

            <div
              v-for="(relation, index) in nodeEditDialog.form.relations
                .slice()
                .reverse()"
              :key="nodeEditDialog.form.relations.length - 1 - index"
              class="relation-item"
            >
              <div class="relation-header">
                <span class="relation-index"
                  ># {{ nodeEditDialog.form.relations.length - index }}</span
                >
                <button
                  class="btn-remove"
                  @click="
                    _removeRelation(
                      nodeEditDialog.form.relations.length - 1 - index
                    )
                  "
                >
                  <i class="icon-delete"></i>
                  删除
                </button>
              </div>

              <div class="relation-form">
                <div class="form-row">
                  <div class="form-group">
                    <label>关系类型</label>
                    <el-select
                      v-model="relation.label"
                      placeholder="请选择关系类型"
                      filterable
                      clearable
                      style="width: 100%"
                    >
                      <el-option
                        v-for="(relationType, index) in relationTypes"
                        :key="index"
                        :value="relationType.label || relationType.name"
                        :label="relationType.label || relationType.name"
                      />
                    </el-select>
                  </div>
                </div>

                <div class="form-row direction-row">
                  <div class="form-group">
                    <label>源节点</label>
                    <div
                      v-if="_isCurrentNodeInPosition(relation, 'source')"
                      class="current-node-display"
                    >
                      <span class="current-node-text">{{
                        _getCurrentNodeLabel()
                      }}</span>
                      <span class="current-node-badge">当前节点</span>
                    </div>
                    <el-select
                      v-else
                      v-model="relation.sourceNodeId"
                      placeholder="请选择源节点"
                      filterable
                      clearable
                      style="width: 100%"
                    >
                      <el-option
                        v-for="node in _getOtherAvailableNodes()"
                        :key="node.id"
                        :value="node.id"
                        :label="node.label"
                        :disabled="node.id === relation.targetNodeId"
                      />
                    </el-select>
                  </div>

                  <div class="direction-switch">
                    <button
                      class="btn-switch"
                      @click="_switchRelationDirection(index)"
                      title="交换源节点和目标节点"
                    >
                      ⇄
                    </button>
                  </div>

                  <div class="form-group">
                    <label>目标节点</label>
                    <div
                      v-if="_isCurrentNodeInPosition(relation, 'target')"
                      class="current-node-display"
                    >
                      <span class="current-node-text">{{
                        _getCurrentNodeLabel()
                      }}</span>
                      <span class="current-node-badge">当前节点</span>
                    </div>
                    <el-select
                      v-else
                      v-model="relation.targetNodeId"
                      placeholder="请选择目标节点"
                      filterable
                      clearable
                      style="width: 100%"
                    >
                      <el-option
                        v-for="node in _getOtherAvailableNodes()"
                        :key="node.id"
                        :value="node.id"
                        :label="node.label"
                        :disabled="node.id === relation.sourceNodeId"
                      />
                    </el-select>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 抽屉底部按钮 -->
        <div class="drawer-footer">
          <el-button @click="_handleDrawerClose">取消</el-button>
          <el-button type="primary" @click="__handleDrawerConfirm">
            {{ nodeEditDialog.isAdd ? "添加" : "保存" }}
          </el-button>
        </div>
      </div>
    </el-drawer>

    <!-- 关系编辑抽屉 -->
    <el-drawer
      v-model="relationEditDialog.visible"
      title="编辑关系"
      direction="rtl"
      size="500px"
      :before-close="_handleRelationDrawerClose"
      destroy-on-close
    >
      <div class="drawer-content">
        <div class="drawer-body">
          <!-- 关系基本信息 -->
          <div class="form-section">
            <h4>关系信息</h4>
            <div class="form-row">
              <div class="form-group">
                <label>关系类型</label>
                <el-select
                  v-model="relationEditDialog.form.relationLabel"
                  placeholder="请选择关系类型"
                  filterable
                  clearable
                  style="width: 100%"
                >
                  <el-option
                    v-for="(relationType, index) in relationTypes"
                    :key="index"
                    :value="relationType.label || relationType.name"
                    :label="relationType.label || relationType.name"
                  />
                </el-select>
              </div>
            </div>
          </div>

          <!-- 节点关系方向 -->
          <div class="form-section">
            <h4>关系方向</h4>
            <div class="relation-direction-container">
              <div class="direction-row">
                <div class="node-info source-node">
                  <div class="node-label">源节点</div>
                  <div class="node-display">
                    <span class="node-name">{{ _getSourceNodeName() }}</span>
                    <span class="node-type">({{ _getSourceNodeType() }})</span>
                  </div>
                </div>

                <div class="direction-arrow">
                  <button
                    class="btn-switch-direction"
                    @click="_switchRelationNodes"
                    title="交换源节点和目标节点"
                  >
                    ⇄
                  </button>
                </div>

                <div class="node-info target-node">
                  <div class="node-label">目标节点</div>
                  <div class="node-display">
                    <span class="node-name">{{ _getTargetNodeName() }}</span>
                    <span class="node-type">({{ _getTargetNodeType() }})</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>

        <!-- 抽屉底部按钮 -->
        <div class="drawer-footer">
          <el-button @click="_handleRelationDrawerClose">取消</el-button>
          <el-button type="primary" @click="_handleRelationDrawerConfirm">
            保存
          </el-button>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<script>
import * as d3 from "d3";

export default {
  name: "DynamicNetworkGraph",
  props: {
    // 初始化数据
    initialData: {
      type: Object,
      default: () => ({ nodes: [], links: [] }),
      validator(value) {
        return (
          value && Array.isArray(value.nodes) && Array.isArray(value.links)
        );
      },
    },

    // 默认节点样式
    defaultNodeStyle: {
      type: Object,
      default: () => ({
        color: "#4E84E4",
        size: 30,
      }),
    },

    // 布局配置
    layoutConfig: {
      type: Object,
      default: () => ({
        linkDistance: 150,
        chargeStrength: -120,
        friction: 0.6,
        centeringStrength: 0.05,
        collisionRadius: 5,
      }),
    },
    isEditor: {
      type: Boolean,
      default: false,
    },

    // 连线样式配置
    linkStyle: {
      type: Object,
      default: () => ({
        type: "curve", // 'straight' | 'curve'
        curvature: 0.1, // 曲线弯曲程度 (0-1)
      }),
    },

    // 关系类型列表
    relationTypes: {
      type: Array,
      default: () => [],
    },
    // 节点类型列表
    nodeTypes: {
      type: Array,
      default: () => [],
    },
  },

  data() {
    return {
      // D3 实例
      svg: null,
      zoomGroup: null,
      simulation: null,
      zoom: null,

      // 数据
      nodes: [],
      links: [],

      // 性能优化相关
      validLinks: [], // 预处理的有效连线
      nodeNeighbors: new Map(), // 节点邻居缓存
      nodeMap: new Map(), // 全局节点ID到对象的映射缓存
      tickTimer: null, // tick节流定时器
      lastViewBox: null, // 上次视窗边界缓存

      // 视图状态
      width: 800,
      height: 600,

      // 拖拽状态
      draggedNode: null,

      // 交互状态
      focusedNode: null,
      hoveredNode: null,
      hoverTimer: null,

      // 右键菜单
      contextMenu: {
        visible: false,
        x: 0,
        y: 0,
        currentNode: null,
      },
      // 节点编辑弹框
      nodeEditDialog: {
        visible: false,
        isAdd: false,
        form: {
          nodeId: null,
          nodeName: "",
          nodeType: "",
          relations: [],
        },
      },
      currentEditNode: null,

      // 关系编辑抽屉
      relationEditDialog: {
        visible: false,
        form: {
          sourceNodeId: "",
          targetNodeId: "",
          relationLabel: "",
          originalSourceId: "", // 用于记录原始关系，便于更新
          originalTargetId: "",
        },
      },
      currentEditRelation: null,
    };
  },

  watch: {
    initialData: {
      deep: true,
      handler() {
        // this._processInitialData();
      },
    },
    // 监听linkStyle变化，重新渲染连线
    linkStyle: {
      handler(newStyle, oldStyle) {
        if (this.simulation && newStyle !== oldStyle) {
          this._renderLinks();
        }
      },
      deep: true,
    },
  },
  computed: {
    nodeTypeMap() {
      const nodeTypeMap = new Map();
      this.nodeTypes.forEach((nodeType) => {
        nodeTypeMap.set(nodeType.label || nodeType.name, nodeType);
      });
      return nodeTypeMap;
    },
    relationTypeMap() {
      const relationTypeMap = new Map();
      this.relationTypes.forEach((relationType) => {
        relationTypeMap.set(
          relationType.label || relationType.name,
          relationType
        );
      });
      return relationTypeMap;
    },
    availableNodes() {
      // 这个计算属性现在主要用于内部逻辑
      let nodes = [];

      if (this.nodeEditDialog.isAdd) {
        nodes = [...this.nodes];
      } else {
        nodes = this.nodes.filter(
          (node) => node.id !== this.nodeEditDialog.form.nodeId
        );
      }

      return nodes;
    },

    // 获取当前操作节点的ID
    currentNodeId() {
      if (this.nodeEditDialog.isAdd) {
        return "__NEW_NODE__";
      } else {
        return this.nodeEditDialog.form.nodeId;
      }
    },

    // 获取当前操作节点的标签
    currentNodeLabel() {
      if (this.nodeEditDialog.isAdd) {
        return this.nodeEditDialog.form.nodeName || "新建节点";
      } else {
        return this.nodeEditDialog.form.nodeName || "当前节点";
      }
    },
  },

  mounted() {
    // 初始化图形
    this._initializeGraph();
    this._processInitialData();
    // 设置事件监听
    this._setupEventListeners();
  },

  beforeUnmount() {
    if (this.simulation) {
      this.simulation.stop();
    }
    this._clearHoverTimer();
    this._clearTickTimer();
    this._removeEventListeners();
  },

  methods: {
    // 初始化图形
    _initializeGraph() {
      const container = this.$refs.container;
      const containerRect = container.getBoundingClientRect();
      this.width = containerRect.width;
      this.height = containerRect.height;

      this.svg = d3
        .select(this.$refs.svg)
        .attr("width", this.width)
        .attr("height", this.height);

      this.zoomGroup = this.svg.select(".zoom-group");

      // 初始化缩放行为
      this.zoom = d3.zoom().scaleExtent([0.1, 4]).on("zoom", this._handleZoom);
      this.svg.call(this.zoom);

      // 初始化视窗边界缓存
      this.lastViewBox = this._calculateViewBox();

      // 初始化力模拟
      this._initializeSimulation();
    },

    // 缩放处理 - 添加视窗更新
    _handleZoom(event) {
      this.zoomGroup.attr("transform", event.transform);

      // 更新视窗边界缓存（仅在大数据量时使用）
      if (this.nodes.length > 500) {
        this.lastViewBox = this._calculateViewBox();
        // 可以在这里触发视窗裁剪更新，但为了保持功能不变，暂时不实现
      }
    },

    // 初始化力模拟 - 性能优化版本
    _initializeSimulation() {
      const nodeCount = this.nodes.length;

      // 基于节点数量动态调整参数
      const scaleFactor = Math.min(1, 1000 / nodeCount);
      const isLargeDataset = nodeCount > 500;

      this.simulation = d3
        .forceSimulation()
        .force(
          "link",
          d3
            .forceLink()
            .id((d) => d.id)
            .distance(this.layoutConfig.linkDistance)
            .iterations(Math.max(1, Math.floor(3 * scaleFactor))) // 减少迭代次数
        )
        .force(
          "charge",
          d3
            .forceManyBody()
            .strength(this.layoutConfig.chargeStrength * scaleFactor)
            .theta(isLargeDataset ? 1.2 : 0.9) // Barnes-Hut算法优化
        )
        .force(
          "center",
          d3
            .forceCenter(this.width / 2, this.height / 2)
            .strength(this.layoutConfig.centeringStrength)
        )
        .force(
          "collision",
          d3
            .forceCollide()
            .radius(
              (d) =>
                (d.size || this.defaultNodeStyle.size) / 2 +
                this.layoutConfig.collisionRadius
            )
            .iterations(isLargeDataset ? 1 : 2) // 大数据量时减少碰撞检测
        )
        .velocityDecay(1 - this.layoutConfig.friction)
        .alpha(isLargeDataset ? 0.1 : 0.3) // 大数据量时降低初始动画强度
        .alphaDecay(isLargeDataset ? 0.05 : 0.0228) // 加快收敛
        .on("tick", this._handleTickOptimized)
        .on("end", () => {
          this.isAnimating = false;
        });
    },

    // 处理初始化数据 - 添加数据预处理和缓存
    _processInitialData() {
      // 深拷贝并处理节点数据
      this.nodes = this.initialData.nodes.map((node) => ({
        ...node,
        color:
          node.color ||
          this.nodeTypeMap.get(node.type).color ||
          this.defaultNodeStyle.color,
        size:
          node.size ||
          this.nodeTypeMap.get(node.type).size ||
          this.defaultNodeStyle.size,
        // D3 内部使用的属性
        x: Math.random() * this.width,
        y: Math.random() * this.height,
        vx: 0,
        vy: 0,
      }));

      // 深拷贝连接数据
      this.links = [...this.initialData.links];

      // 构建全局nodeMap缓存
      this._buildNodeMap();

      // 预处理和缓存有效连线
      this._preprocessLinkData();

      // 更新模拟和渲染
      this._updateSimulation();
      this._renderGraph();
    },

    // 构建全局nodeMap缓存
    _buildNodeMap() {
      this.nodeMap.clear();
      this.nodes.forEach((node) => {
        this.nodeMap.set(node.id, node);
      });
      console.log(`构建 nodeMap 完成，包含 ${this.nodeMap.size} 个节点`);
    },

    // 更新nodeMap中的单个节点
    _updateNodeInMap(node) {
      if (node && node.id) {
        this.nodeMap.set(node.id, node);
      }
    },

    // 从 nodeMap 中删除节点
    _removeNodeFromMap(nodeId) {
      this.nodeMap.delete(nodeId);
    },

    // 获取节点（替换 find 操作）
    _getNodeById(nodeId) {
      return this.nodeMap.get(nodeId) || null;
    },

    // 预处理连线数据和创建邻居缓存
    _preprocessLinkData() {
      // 预处理并缓存有效连线
      this.validLinks = this.links.filter((link) => {
        const sourceId = link.source && (link.source.id || link.source);
        const targetId = link.target && (link.target.id || link.target);

        if (!sourceId || !targetId) {
          return false;
        }

        // 确保节点存在
        const sourceExists = this._getNodeById(sourceId);
        const targetExists = this._getNodeById(targetId);

        return sourceExists && targetExists;
      });

      // 预计算节点邻居表
      this.nodeNeighbors = new Map();
      this.validLinks.forEach((link) => {
        const sourceId = link.source.id || link.source;
        const targetId = link.target.id || link.target;

        if (!this.nodeNeighbors.has(sourceId)) {
          this.nodeNeighbors.set(sourceId, new Set());
        }
        if (!this.nodeNeighbors.has(targetId)) {
          this.nodeNeighbors.set(targetId, new Set());
        }

        this.nodeNeighbors.get(sourceId).add(targetId);
        this.nodeNeighbors.get(targetId).add(sourceId);
      });
    },

    // 更新力模拟 - 使用预处理的数据
    _updateSimulation() {
      if (!this.simulation) return;

      // 使用预处理的有效连线，避免重复验证
      this.simulation.nodes(this.nodes).force("link").links(this.validLinks);

      // 重启模拟
      this.simulation.alpha(0.1).restart();
    },

    // 渲染图形
    _renderGraph() {
      this._renderLinks();
      this._renderNodes();
      this._renderLabels();
    },

    // 渲染连接线 - 使用预处理的数据，支持视窗裁剪
    _renderLinks() {
      const linksGroup = this.zoomGroup.select(".links-group");

      // 使用视窗裁剪优化（在大数据量时）
      const validLinks = this._getVisibleLinks();

      // 完全清除所有连接相关元素，避免样式切换时的冲突
      linksGroup.selectAll("*").remove();

      // 根据连线样式创建对应的元素
      if (this.linkStyle.type === "curve") {
        // 创建曲线连接（path元素）
        linksGroup
          .selectAll(".link")
          .data(validLinks)
          .enter()
          .append("path")
          .attr("class", "link")
          .attr("fill", "none")
          .attr("stroke", "#999")
          .attr("stroke-width", 1)
          .attr("stroke-dasharray", (d) => {
            d.isHierarchy =
              d.isHierarchy ||
              this.relationTypeMap.get(d.label).isHierarchy ||
              false;
            return d.isHierarchy === true ? "none" : "5,5";
          })
          .attr("marker-end", (d) => {
            d.isHierarchy =
              d.isHierarchy ||
              this.relationTypeMap.get(d.label).isHierarchy ||
              false;
            return d.isHierarchy === true ? "url(#arrowhead)" : "none";
          })
          .attr("d", (d) => this._generateCurvePath(d));

        // 在编辑模式下为连线添加双击事件
        if (this.isEditor) {
          linksGroup.selectAll(".link").style("cursor", "pointer");
        }
      } else {
        // 创建直线连接（line元素）
        linksGroup
          .selectAll(".link")
          .data(validLinks)
          .enter()
          .append("line")
          .attr("class", "link")
          .attr("stroke", "#999")
          .attr("stroke-width", 1)
          .attr("stroke-dasharray", (d) =>
            d.isHierarchy === true ? "none" : "5,5"
          )
          .attr("marker-end", (d) =>
            d.isHierarchy === true ? "url(#arrowhead)" : "none"
          )
          .attr("x1", (d) => {
            const sourceRadius =
              (d.source.size || this.defaultNodeStyle.size) / 2;
            return this._getEdgePosition(d.source, d.target, sourceRadius).x;
          })
          .attr("y1", (d) => {
            const sourceRadius =
              (d.source.size || this.defaultNodeStyle.size) / 2;
            return this._getEdgePosition(d.source, d.target, sourceRadius).y;
          })
          .attr("x2", (d) => {
            const targetRadius =
              (d.target.size || this.defaultNodeStyle.size) / 2;
            return this._getEdgePosition(d.target, d.source, targetRadius).x;
          })
          .attr("y2", (d) => {
            const targetRadius =
              (d.target.size || this.defaultNodeStyle.size) / 2;
            return this._getEdgePosition(d.target, d.source, targetRadius).y;
          });

        // 在编辑模式下为连线添加双击事件
        if (this.isEditor) {
          linksGroup.selectAll(".link").style("cursor", "pointer");
        }
      }

      // 添加连接标签（如果有）
      this._renderLinkLabels();
    },

    // 渲染连接标签
    _renderLinkLabels() {
      const linksGroup = this.zoomGroup.select(".links-group");

      // 过滤有效且有标签的连接 - 使用预处理数据
      const validLinksWithLabels = this.validLinks.filter((d) => d.label);

      // 创建连接标签
      const labelElements = linksGroup
        .selectAll(".link-label")
        .data(validLinksWithLabels)
        .enter()
        .append("text")
        .attr("class", "link-label")
        .text((d) => d.label)
        .attr("text-anchor", "middle")
        .attr("font-size", "10px")
        .attr("fill", "#666")
        .attr("x", (d) => this._getLinkLabelPosition(d).x)
        .attr("y", (d) => this._getLinkLabelPosition(d).y)
        .classed("editable", this.isEditor);

      // 在编辑模式下添加双击事件
      if (this.isEditor) {
        labelElements.on("dblclick", this._handleLinkLabelDoubleClick);
      }
    },

    // 渲染节点 - 支持视窗裁剪优化
    _renderNodes() {
      const nodesGroup = this.zoomGroup.select(".nodes-group");

      // 使用视窗裁剪优化（在大数据量时）
      const visibleNodes = this._getVisibleNodes();

      const nodes = nodesGroup
        .selectAll(".node-group")
        .data(visibleNodes, (d) => d.id);

      // 移除多余的节点
      nodes.exit().remove();

      // 添加新节点
      const nodeEnter = nodes.enter().append("g").attr("class", "node-group");

      // 节点圆圈
      nodeEnter
        .append("circle")
        .attr("class", "node-circle")
        .attr("r", (d) => d.size / 2)
        .attr("fill", (d) => d.color)
        .style("cursor", "move");

      // 合并和更新
      const nodeUpdate = nodes.merge(nodeEnter);

      nodeUpdate
        .select(".node-circle")
        .attr("r", (d) => d.size / 2)
        .attr("fill", (d) => d.color);

      // 添加拖拽行为和交互事件
      nodeUpdate
        .call(this._createDragBehavior())
        .on("click", this._handleNodeClick)
        .on("contextmenu", this._handleNodeContextMenu)
        .on("mouseenter", this._handleNodeMouseEnter)
        .on("mouseleave", this._handleNodeMouseLeave);
    },

    // 渲染节点标签 - 支持视窗裁剪优化
    _renderLabels() {
      const labelsGroup = this.zoomGroup.select(".labels-group");

      // 使用视窗裁剪优化（在大数据量时）
      const visibleNodes = this._getVisibleNodes();

      const labels = labelsGroup
        .selectAll(".node-label")
        .data(visibleNodes, (d) => d.id);

      labels.exit().remove();

      const labelEnter = labels
        .enter()
        .append("text")
        .attr("class", "node-label");

      const labelUpdate = labels.merge(labelEnter);

      labelUpdate.text((d) => d.label).classed("editable", this.isEditor);

      // 在编辑模式下添加双击事件
      if (this.isEditor) {
        labelUpdate.on("dblclick", this._handleLabelDoubleClick);
      } else {
        labelUpdate.on("dblclick", null); // 清除双击事件
      }
    },

    // Tick 处理 - 优化版本，使用requestAnimationFrame节流
    _handleTickOptimized() {
      // 使用 requestAnimationFrame 节流，避免过度更新
      if (this.tickTimer) return;

      this.tickTimer = requestAnimationFrame(() => {
        if (this.linkStyle.type === "curve") {
          // 更新曲线连接位置
          this.zoomGroup.selectAll(".link").attr("d", (d) => {
            return this._generateCurvePath(d);
          });
        } else {
          // 更新直线连接位置 - 计算节点边缘位置
          this.zoomGroup
            .selectAll(".link")
            .attr("x1", (d) => {
              const sourceRadius =
                (d.source.size || this.defaultNodeStyle.size) / 2;
              return this._getEdgePosition(d.source, d.target, sourceRadius).x;
            })
            .attr("y1", (d) => {
              const sourceRadius =
                (d.source.size || this.defaultNodeStyle.size) / 2;
              return this._getEdgePosition(d.source, d.target, sourceRadius).y;
            })
            .attr("x2", (d) => {
              const targetRadius =
                (d.target.size || this.defaultNodeStyle.size) / 2;
              return this._getEdgePosition(d.target, d.source, targetRadius).x;
            })
            .attr("y2", (d) => {
              const targetRadius =
                (d.target.size || this.defaultNodeStyle.size) / 2;
              return this._getEdgePosition(d.target, d.source, targetRadius).y;
            });
        }

        // 更新连接标签位置
        this.zoomGroup
          .selectAll(".link-label")
          .attr("x", (d) => {
            return this._getLinkLabelPosition(d).x;
          })
          .attr("y", (d) => {
            return this._getLinkLabelPosition(d).y;
          });

        // 更新节点位置
        this.zoomGroup
          .selectAll(".node-group")
          .attr("transform", (d) => `translate(${d.x}, ${d.y})`);

        // 更新标签位置
        this.zoomGroup
          .selectAll(".node-label")
          .attr("x", (d) => d.x)
          .attr(
            "y",
            (d) => d.y + (d.size || this.defaultNodeStyle.size) / 2 + 15
          );

        this.tickTimer = null;
      });
    },

    // 清除tick定时器
    _clearTickTimer() {
      if (this.tickTimer) {
        cancelAnimationFrame(this.tickTimer);
        this.tickTimer = null;
      }
    },

    // 创建拖拽行为
    _createDragBehavior() {
      return d3
        .drag()
        .on("start", this.__handleDragStart)
        .on("drag", this._handleDrag)
        .on("end", this._handleDragEnd);
    },

    // 拖拽开始
    __handleDragStart(event, node) {
      if (!event.active) this.simulation.alphaTarget(0.3).restart();

      this.draggedNode = node;
      node.fx = node.x;
      node.fy = node.y;

      // 拖拽时清除悬停状态
      this._clearHoverTimer();
      this._clearHoverHighlight();
    },

    // 拖拽中
    _handleDrag(event, node) {
      node.fx = event.x;
      node.fy = event.y;
    },

    // 拖拽结束
    _handleDragEnd(event, node) {
      if (!event.active) this.simulation.alphaTarget(0);

      // 保持节点固定在拖拽位置
      node.fx = event.x;
      node.fy = event.y;

      this.draggedNode = null;
    },

    // 节点点击处理
    _handleNodeClick(event, node) {
      event.stopPropagation();

      // 如果点击的是当前焦点节点，则取消焦点
      if (this.focusedNode && this.focusedNode.id === node.id) {
        this._unfocus();
        return;
      }

      // 设置新的焦点节点
      this._focusOnNode(node);
      this.$emit("node-click", node);
    },

    // 聚焦到节点
    _focusOnNode(node) {
      // 清除之前的高亮
      this._clearHighlight();

      // 设置新焦点
      this.focusedNode = node;

      // 高亮节点和相关连线
      const nodeIds = this._highlightNode(node);
      const nodes = this.nodes.filter((node) => {
        return nodeIds.has(node.id);
      });
      // 将节点移动到画布中心
      this._centerToNodes(nodes);
    },

    // 取消焦点
    _unfocus() {
      this.focusedNode = null;
      this._clearHighlight();
    },

    // 高亮节点和相关元素 - 优化版本，使用邻居缓存
    _highlightNode(node) {
      const connectedNodeIds = new Set([node.id]);

      // 使用预计算的邻居表，避免遍历所有连线
      const neighbors = this.nodeNeighbors.get(node.id);
      if (neighbors) {
        neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
      }

      // 高亮节点
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 高亮连接线
      this.zoomGroup
        .selectAll(".link")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return sourceId === node.id || targetId === node.id;
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(sourceId === node.id || targetId === node.id);
        })
        .attr("marker-end", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          const isConnected = sourceId === node.id || targetId === node.id;
          if (d.isHierarchy === true) {
            return isConnected
              ? "url(#arrowhead-highlight)"
              : "url(#arrowhead)";
          } else {
            return "none";
          }
        });

      // 高亮连接标签
      this.zoomGroup
        .selectAll(".link-label")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return sourceId === node.id || targetId === node.id;
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(sourceId === node.id || targetId === node.id);
        });

      // 高亮节点标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      return connectedNodeIds;
    },

    // 计算当前视窗边界（用于视窗裁剪）
    _calculateViewBox() {
      const transform = d3.zoomTransform(this.svg.node());
      return {
        x: -transform.x / transform.k,
        y: -transform.y / transform.k,
        width: this.width / transform.k,
        height: this.height / transform.k,
      };
    },

    // 检查节点是否在视窗内（用于视窗裁剪）
    _isNodeVisible(node, viewBox = null) {
      const vbox = viewBox || this.lastViewBox || this._calculateViewBox();
      const nodeRadius = (node.size || this.defaultNodeStyle.size) / 2;
      const padding = 50; // 额外填充，确保边缘节点也被渲染

      return (
        node.x >= vbox.x - nodeRadius - padding &&
        node.x <= vbox.x + vbox.width + nodeRadius + padding &&
        node.y >= vbox.y - nodeRadius - padding &&
        node.y <= vbox.y + vbox.height + nodeRadius + padding
      );
    },

    // 获取可见节点（用于视窗裁剪优化）
    _getVisibleNodes() {
      // 只有在节点数量较大时才启用视窗裁剪
      if (this.nodes.length <= 500) {
        return this.nodes;
      }

      const viewBox = this._calculateViewBox();
      return this.nodes.filter((node) => this._isNodeVisible(node, viewBox));
    },

    // 获取可见连线（用于视窗裁剪优化）
    _getVisibleLinks() {
      // 只有在节点数量较大时才启用视窗裁剪
      if (this.nodes.length <= 500) {
        return this.validLinks;
      }

      const viewBox = this._calculateViewBox();
      return this.validLinks.filter((link) => {
        const sourceId = link.source.id || link.source;
        const targetId = link.target.id || link.target;
        const sourceNode = this.nodes.find((n) => n.id === sourceId);
        const targetNode = this.nodes.find((n) => n.id === targetId);

        // 连线可见的条件：至少一个节点在视窗内
        return (
          sourceNode &&
          targetNode &&
          (this._isNodeVisible(sourceNode, viewBox) ||
            this._isNodeVisible(targetNode, viewBox))
        );
      });
    },

    // 清除高亮
    _clearHighlight() {
      this.zoomGroup
        .selectAll(".node-group, .link, .link-label, .node-label")
        .classed("highlighted", false)
        .classed("dimmed", false);

      // 恢复默认箭头（根据isHierarchy属性）
      this.zoomGroup
        .selectAll(".link")
        .attr("marker-end", (d) =>
          d.isHierarchy === true ? "url(#arrowhead)" : "none"
        );
    },

    // 将节点移动到画布中心
    _centerToNode(node) {
      const transform = d3.zoomTransform(this.svg.node());
      const x = -node.x * transform.k + this.width / 2;
      const y = -node.y * transform.k + this.height / 2;

      this.svg
        .transition()
        .duration(750)
        .call(
          this.zoom.transform,
          d3.zoomIdentity.translate(x, y).scale(transform.k)
        );
    },

    // 将多个节点的中心移动到画布中央
    _centerToNodes(nodes) {
      if (!nodes || nodes.length === 0) return;

      // 计算所有节点的中心点
      let centerX = 0,
        centerY = 0;
      nodes.forEach((node) => {
        centerX += node.x;
        centerY += node.y;
      });
      centerX /= nodes.length;
      centerY /= nodes.length;

      // 计算所有节点的边界框
      let minX = Infinity,
        maxX = -Infinity,
        minY = Infinity,
        maxY = -Infinity;
      nodes.forEach((node) => {
        const radius = (node.size || this.defaultNodeStyle.size) / 2;
        minX = Math.min(minX, node.x - radius);
        maxX = Math.max(maxX, node.x + radius);
        minY = Math.min(minY, node.y - radius);
        maxY = Math.max(maxY, node.y + radius);
      });

      const boundsWidth = maxX - minX;
      const boundsHeight = maxY - minY;

      // 计算合适的缩放比例，确保所有节点都在视图中
      const padding = 50; // 边距
      const scaleX = (this.width - padding * 2) / boundsWidth;
      const scaleY = (this.height - padding * 2) / boundsHeight;
      let targetScale = Math.min(scaleX, scaleY);

      // 限制缩放范围
      const currentTransform = d3.zoomTransform(this.svg.node());
      targetScale = Math.min(Math.max(targetScale, 0.1), 4); // 与zoom的scaleExtent一致

      // 如果只有单个节点或节点很集中，保持当前缩放
      if (boundsWidth < 100 && boundsHeight < 100) {
        // targetScale = currentTransform.k;
        targetScale = currentTransform.k < 1.5 ? 1.5 : currentTransform.k;
      }

      // 计算平移参数
      const x = -centerX * targetScale + this.width / 2;
      const y = -centerY * targetScale + this.height / 2;

      // 应用动画变换
      this.svg
        .transition()
        .duration(750)
        .call(
          this.zoom.transform,
          d3.zoomIdentity.translate(x, y).scale(targetScale)
        );
    },

    // 画布点击处理
    _handleCanvasClick() {
      this._hideContextMenu();
      this._unfocus();
    },

    // 节点鼠标进入处理
    _handleNodeMouseEnter(event, node) {
      // 如果正在拖拽或已有焦点节点，则不处理悬停
      if (this.draggedNode || this.focusedNode) return;

      // 清除之前的定时器
      this._clearHoverTimer();

      // 设置延迟定时器，避免快速滑动时频繁触发
      this.hoverTimer = setTimeout(() => {
        this.hoveredNode = node;
        this._highlightNodeOnHover(node);
      }, 200); // 200ms 延迟
    },

    // 节点鼠标离开处理
    _handleNodeMouseLeave(event, node) {
      // 如果正在拖拽或已有焦点节点，则不处理悬停
      if (this.draggedNode || this.focusedNode) return;

      // 清除定时器和悬停高亮
      this._clearHoverTimer();
      this._clearHoverHighlight();
    },

    // 悬停高亮节点和相关元素 - 优化版本，使用邻居缓存
    _highlightNodeOnHover(node) {
      const connectedNodeIds = new Set([node.id]);

      // 使用预计算的邻居表，避免遍历所有连线
      const neighbors = this.nodeNeighbors.get(node.id);
      if (neighbors) {
        neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
      }

      // 悬停高亮节点
      this.zoomGroup
        .selectAll(".node-group")
        .classed("hover-highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("hover-dimmed", (d) => !connectedNodeIds.has(d.id));

      // 悬停高亮连接线
      this.zoomGroup
        .selectAll(".link")
        .classed("hover-highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return sourceId === node.id || targetId === node.id;
        })
        .classed("hover-dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(sourceId === node.id || targetId === node.id);
        })
        .attr("marker-end", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          const isConnected = sourceId === node.id || targetId === node.id;
          if (d.isHierarchy === true) {
            return isConnected
              ? "url(#arrowhead-highlight)"
              : "url(#arrowhead)";
          } else {
            return "none";
          }
        });

      // 悬停高亮连接标签
      this.zoomGroup
        .selectAll(".link-label")
        .classed("hover-highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return sourceId === node.id || targetId === node.id;
        })
        .classed("hover-dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(sourceId === node.id || targetId === node.id);
        });

      // 悬停高亮节点标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("hover-highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("hover-dimmed", (d) => !connectedNodeIds.has(d.id));
    },

    // 清除悬停高亮
    _clearHoverHighlight() {
      this.hoveredNode = null;
      this.zoomGroup
        .selectAll(".node-group, .link, .link-label, .node-label")
        .classed("hover-highlighted", false)
        .classed("hover-dimmed", false);

      // 恢复默认箭头（如果没有焦点节点）
      if (!this.focusedNode) {
        this.zoomGroup
          .selectAll(".link")
          .attr("marker-end", (d) =>
            d.isHierarchy === true ? "url(#arrowhead)" : "none"
          );
      }
    },

    // 清除悬停定时器
    _clearHoverTimer() {
      if (this.hoverTimer) {
        clearTimeout(this.hoverTimer);
        this.hoverTimer = null;
      }
    },

    // 计算节点边缘位置
    _getEdgePosition(sourceNode, targetNode, radius) {
      const dx = targetNode.x - sourceNode.x;
      const dy = targetNode.y - sourceNode.y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      // 避免除零错误
      if (distance === 0) {
        return { x: sourceNode.x, y: sourceNode.y };
      }

      // 计算单位向量
      const unitX = dx / distance;
      const unitY = dy / distance;

      // 返回节点边缘位置
      return {
        x: sourceNode.x + unitX * radius,
        y: sourceNode.y + unitY * radius,
      };
    },

    // 生成曲线路径
    _generateCurvePath(linkData) {
      const sourceRadius =
        (linkData.source.size || this.defaultNodeStyle.size) / 2;
      const targetRadius =
        (linkData.target.size || this.defaultNodeStyle.size) / 2;

      // 计算起点和终点在节点边缘的位置
      const sourceEdge = this._getEdgePosition(
        linkData.source,
        linkData.target,
        sourceRadius
      );
      const targetEdge = this._getEdgePosition(
        linkData.target,
        linkData.source,
        targetRadius
      );

      // 计算中点
      const midX = (sourceEdge.x + targetEdge.x) / 2;
      const midY = (sourceEdge.y + targetEdge.y) / 2;

      // 计算控制点 - 在中点的垂直方向上偏移
      const dx = targetEdge.x - sourceEdge.x;
      const dy = targetEdge.y - sourceEdge.y;
      const distance = Math.sqrt(dx * dx + dy * dy);

      // 避免除零错误
      if (distance === 0) {
        return `M ${sourceEdge.x},${sourceEdge.y} L ${targetEdge.x},${targetEdge.y}`;
      }

      // 计算垂直于连线的向量
      const perpX = -dy / distance;
      const perpY = dx / distance;

      // 根据curvature参数计算控制点偏移距离
      const offset = distance * this.linkStyle.curvature;
      const controlX = midX + perpX * offset;
      const controlY = midY + perpY * offset;

      // 生成二次贝塞尔曲线路径
      return `M ${sourceEdge.x},${sourceEdge.y} Q ${controlX},${controlY} ${targetEdge.x},${targetEdge.y}`;
    },

    // 获取连接标签位置
    _getLinkLabelPosition(linkData) {
      const sourceRadius =
        (linkData.source.size || this.defaultNodeStyle.size) / 2;
      const targetRadius =
        (linkData.target.size || this.defaultNodeStyle.size) / 2;

      const sourceEdge = this._getEdgePosition(
        linkData.source,
        linkData.target,
        sourceRadius
      );
      const targetEdge = this._getEdgePosition(
        linkData.target,
        linkData.source,
        targetRadius
      );

      if (this.linkStyle.type === "curve") {
        // 对于曲线，标签放在贝塞尔曲线的中点
        const midX = (sourceEdge.x + targetEdge.x) / 2;
        const midY = (sourceEdge.y + targetEdge.y) / 2;

        const dx = targetEdge.x - sourceEdge.x;
        const dy = targetEdge.y - sourceEdge.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance === 0) {
          return { x: midX, y: midY };
        }

        // 计算垂直于连线的向量
        const perpX = -dy / distance;
        const perpY = dx / distance;

        // 根据curvature参数计算标签位置（在曲线的中间点）
        const offset = distance * this.linkStyle.curvature * 0.5; // 标签位置在控制点和直线中点之间
        return {
          x: midX + perpX * offset,
          y: midY + perpY * offset,
        };
      } else {
        // 对于直线，标签放在直线中点
        return {
          x: (sourceEdge.x + targetEdge.x) / 2,
          y: (sourceEdge.y + targetEdge.y) / 2,
        };
      }
    },

    // 节点右键处理
    _handleNodeContextMenu(event, node) {
      event.preventDefault();
      event.stopPropagation();

      // 如果不是编辑模式，不显示右键菜单
      if (!this.isEditor) {
        return;
      }

      const containerRect = this.$refs.container.getBoundingClientRect();
      this.contextMenu = {
        visible: true,
        x: event.clientX - containerRect.left,
        y: event.clientY - containerRect.top,
        currentNode: node,
      };
    },

    // 隐藏右键菜单
    _hideContextMenu() {
      this.contextMenu.visible = false;
      this.contextMenu.currentNode = null;
    },

    // 右键删除当前节点，并通知父级删除操作
    _handleDeleteNode() {
      const node = this.contextMenu.currentNode;
      this.$confirm(`确定要删除节点"${node.label}"吗？`, "删除确认", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.removeNodeById(node.id);
          this.$emit("delete-node", node);
        })
        .catch(() => {
          // 用户取消删除
        });
      this._hideContextMenu();
    },

    // 右键添加节点
    _handleAddNode() {
      const contextNode = this.contextMenu.currentNode;
      this._hideContextMenu();
      this._openAddNodeDialog(contextNode);
    },

    // 右键编辑当前节点
    _handleEditNode() {
      const contextNode = this.contextMenu.currentNode;
      this._hideContextMenu();
      this._openEditNodeDialog(contextNode);
    },

    // 处理节点标签双击事件
    _handleLabelDoubleClick(event, node) {
      event.preventDefault();
      event.stopPropagation();

      // 如果不是编辑模式，不响应双击
      if (!this.isEditor) {
        return;
      }

      // 隐藏右键菜单（如果有的话）
      this._hideContextMenu();
      this._openEditNodeDialog(node);
    },

    // ======= 节点编辑相关方法 =======

    // 打开添加节点弹框
    _openAddNodeDialog(contextNode) {
      this.nodeEditDialog.visible = true;
      this.nodeEditDialog.isAdd = true;
      this.nodeEditDialog.form = {
        nodeId: this.currentNodeId,
        nodeName: "",
        nodeType: "",
        relations: [],
      };
      this.currentEditNode = contextNode;
    },

    // 打开编辑节点弹框 - 性能优化版本
    _openEditNodeDialog(node) {
      const startTime = performance.now();

      const relationInfo = this.getNodeRelations(node.id);

      const getRelationsTime = performance.now();

      this.nodeEditDialog.visible = true;
      this.nodeEditDialog.isAdd = false;
      this.nodeEditDialog.form = {
        nodeId: node.id,
        nodeName: node.label,
        nodeType: node.type || "",
        relations: relationInfo
          ? relationInfo.relationships.map((rel) => ({
              sourceNodeId: rel.link.source,
              targetNodeId: rel.link.target,
              label: rel.link.label || "",
              isHierarchy: rel.link.isHierarchy, // 直接使用已优化计算的值
            }))
          : [],
      };
      this.currentEditNode = node;

      const totalTime = performance.now();

      // 性能日志（仅在开发环境下显示）
      if (process.env.NODE_ENV === "development") {
        const relationCount = relationInfo
          ? relationInfo.relationships.length
          : 0;
        console.log(`节点编辑对话框性能统计:`);
        console.log(
          `  - 获取关系耗时: ${(getRelationsTime - startTime).toFixed(2)}ms`
        );
        console.log(
          `  - 数据处理耗时: ${(totalTime - getRelationsTime).toFixed(2)}ms`
        );
        console.log(`  - 总耗时: ${(totalTime - startTime).toFixed(2)}ms`);
        console.log(`  - 关系数量: ${relationCount}`);
      }
    },

    // 抽屉关闭处理
    _handleDrawerClose() {
      this.nodeEditDialog.visible = false;
      this._resetDialogForm();
    },

    // 弹框确认处理
    __handleDrawerConfirm() {
      if (this._validateForm()) {
        if (this.nodeEditDialog.isAdd) {
          this._handleAddNodeConfirm();
        } else {
          this._handleEditNodeConfirm();
        }
      }
    },

    // 处理添加节点确认
    _handleAddNodeConfirm() {
      const form = this.nodeEditDialog.form;

      // 生成新的节点ID
      const newNodeId = `node_${Date.now()}_${Math.random()
        .toString(36)
        .substring(2, 9)}`;

      // 构造新节点数据
      const newNode = {
        id: newNodeId,
        label: form.nodeName.trim(),
        type: form.nodeType,
      };

      // 构造关系数据 - 只包含有效的关系，并处理新节点的引用
      const relationList = form.relations
        .filter((relation) => relation.sourceNodeId && relation.targetNodeId)
        .map((relation) => ({
          source:
            relation.sourceNodeId === "__NEW_NODE__"
              ? newNodeId
              : relation.sourceNodeId,
          target:
            relation.targetNodeId === "__NEW_NODE__"
              ? newNodeId
              : relation.targetNodeId,
          label: relation.label || "",
          isHierarchy:
            relation.isHierarchy ||
            this.relationTypeMap.get(relation.label).isHierarchy ||
            false,
        }));

      try {
        // 调用组件的addNode方法
        const result = this.addNode(newNode, relationList);

        if (result) {
          this.$message?.success("节点添加成功");
          this.nodeEditDialog.visible = false;
          this._resetDialogForm();

          // 发送事件通知
          this.$emit("node-added", {
            node: result,
            relationList: relationList,
          });
        } else {
          this.$message?.error("节点添加失败");
        }
      } catch (error) {
        console.error("添加节点时发生错误:", error);
        this.$message?.error("添加节点时发生错误: " + error.message);
      }
    },

    // 处理编辑节点确认
    _handleEditNodeConfirm() {
      const form = this.nodeEditDialog.form;

      // 构造节点更新数据
      const nodeUpdates = {
        label: form.nodeName.trim(),
        type: form.nodeType,
      };

      // 构造关系更新数据
      const updatedRelationList = form.relations
        .filter((relation) => relation.sourceNodeId && relation.targetNodeId)
        .map((relation) => ({
          source: relation.sourceNodeId,
          target: relation.targetNodeId,
          label: relation.label || "",
          isHierarchy:
            relation.isHierarchy ||
            this.relationTypeMap.get(relation.label).isHierarchy ||
            false,
        }));

      try {
        // 调用组件的editNode方法
        const result = this.editNode(
          form.nodeId,
          nodeUpdates,
          updatedRelationList
        );

        if (result) {
          this.$message?.success("节点编辑成功");
          this.nodeEditDialog.visible = false;
          this._resetDialogForm();

          // 发送事件通知
          this.$emit("node-edited", {
            nodeId: form.nodeId,
            node: nodeUpdates,
            relationList: updatedRelationList,
          });
        } else {
          this.$message?.error("节点编辑失败");
        }
      } catch (error) {
        console.error("编辑节点时发生错误:", error);
        this.$message?.error("编辑节点时发生错误: " + error.message);
      }
    },

    // 重置弹框表单
    _resetDialogForm() {
      this.nodeEditDialog.form = {
        nodeId: null,
        nodeName: "",
        nodeType: "",
        relations: [],
      };
      this.currentEditNode = null;
    },

    // 表单验证
    _validateForm() {
      const form = this.nodeEditDialog.form;

      // 验证节点名称
      if (!form.nodeName || form.nodeName.trim() === "") {
        this.$message?.error("请输入节点名称");
        return false;
      }

      // 验证节点名称长度
      if (form.nodeName.trim().length > 50) {
        this.$message?.error("节点名称长度不能超过50个字符");
        return false;
      }

      // 验证节点类型
      if (!form.nodeType || form.nodeType.trim() === "") {
        this.$message?.error("请选择节点类型");
        return false;
      }

      // 验证节点类型是否存在
      if (!this.nodeTypeMap.has(form.nodeType)) {
        this.$message?.error("选择的节点类型无效，请重新选择");
        return false;
      }

      // 在添加模式下，检查节点名称是否已存在
      if (this.nodeEditDialog.isAdd) {
        const existingNode = this.nodes.find(
          (node) =>
            node.label.trim().toLowerCase() ===
            form.nodeName.trim().toLowerCase()
        );
        if (existingNode) {
          this.$message?.error(
            `节点名称"${form.nodeName.trim()}"已存在，请使用不同的名称`
          );
          return false;
        }
      } else {
        // 在编辑模式下，检查节点名称是否与其他节点冲突
        const existingNode = this.nodes.find(
          (node) =>
            node.id !== form.nodeId &&
            node.label.trim().toLowerCase() ===
              form.nodeName.trim().toLowerCase()
        );
        if (existingNode) {
          this.$message?.error(
            `节点名称"${form.nodeName.trim()}"已被其他节点使用，请使用不同的名称`
          );
          return false;
        }
      }

      // 验证关系
      const relationPairs = new Set(); // 用于检查重复关系
      for (let i = 0; i < form.relations.length; i++) {
        const relation = form.relations[i];

        // 检查源节点和目标节点是否都已选择
        if (!relation.sourceNodeId || !relation.targetNodeId) {
          this.$message?.error(`请完善第 ${i + 1} 个关系的源节点和目标节点`);
          return false;
        }

        // 检查源节点和目标节点是否相同
        if (relation.sourceNodeId === relation.targetNodeId) {
          this.$message?.error(`第 ${i + 1} 个关系的源节点和目标节点不能相同`);
          return false;
        }

        // 检查节点是否存在 - 使用nodeMap优化
        const sourceNode = this._getNodeById(relation.sourceNodeId);
        const targetNode = this._getNodeById(relation.targetNodeId);

        if (!sourceNode && relation.sourceNodeId !== form.nodeId) {
          this.$message?.error(`第 ${i + 1} 个关系的源节点不存在`);
          return false;
        }
        if (!targetNode && relation.targetNodeId !== form.nodeId) {
          this.$message?.error(`第 ${i + 1} 个关系的目标节点不存在`);
          return false;
        }

        // 检查关系类型
        if (relation.label && !this.relationTypeMap.has(relation.label)) {
          this.$message?.error(`第 ${i + 1} 个关系的关系类型无效，请重新选择`);
          return false;
        }

        // 检查重复关系
        const relationKey = `${relation.sourceNodeId}->${relation.targetNodeId}`;
        if (relationPairs.has(relationKey)) {
          this.$message?.error(
            `第 ${i + 1} 个关系与其他关系重复，同一对节点间只能有一个关系`
          );
          return false;
        }
        // 获取关系的isHierarchy属性
        const relationType = this.relationTypeMap.get(relation.label);
        if (relationType) {
          relation.isHierarchy = relationType.isHierarchy || false;
        }
        relationPairs.add(relationKey);
      }

      return true;
    },

    // 添加关系
    _addRelation() {
      let newRelation = {
        sourceNodeId: this.currentNodeId, // 默认将当前节点作为源节点
        targetNodeId: "",
        label: "",
        isHierarchy: false,
      };

      // 将新关系添加到数组的最后面，经过reverse()后显示在列表顶部
      this.nodeEditDialog.form.relations.push(newRelation);
    },

    // 删除关系
    _removeRelation(index) {
      if (index >= 0 && index < this.nodeEditDialog.form.relations.length) {
        this.nodeEditDialog.form.relations.splice(index, 1);
      }
    },

    // 检查当前操作的节点是否在指定位置（源或目标）
    _isCurrentNodeInPosition(relation, position) {
      const currentId = this.currentNodeId;
      if (position === "source") {
        return relation.sourceNodeId === currentId;
      } else if (position === "target") {
        return relation.targetNodeId === currentId;
      }
      return false;
    },

    // 获取当前操作节点的显示标签
    _getCurrentNodeLabel() {
      return this.currentNodeLabel;
    },

    // 获取除当前节点外的其他可用节点
    _getOtherAvailableNodes() {
      return this.availableNodes;
    },

    // 交换关系的源节点和目标节点
    _switchRelationDirection(index) {
      if (index >= 0 && index < this.nodeEditDialog.form.relations.length) {
        const relation = this.nodeEditDialog.form.relations[index];
        const temp = relation.sourceNodeId;
        relation.sourceNodeId = relation.targetNodeId;
        relation.targetNodeId = temp;
      }
    },

    // 处理连线标签双击事件
    _handleLinkLabelDoubleClick(event, link) {
      event.preventDefault();
      event.stopPropagation();

      // 如果不是编辑模式，不响应双击
      if (!this.isEditor) {
        return;
      }

      // 隐藏右键菜单（如果有的话）
      this._hideContextMenu();
      this._openEditRelationDialog(link);
    },

    // ======= 关系编辑相关方法 =======

    // 打开关系编辑抽屉
    _openEditRelationDialog(link) {
      const sourceId = link.source.id || link.source;
      const targetId = link.target.id || link.target;

      this.relationEditDialog.visible = true;
      this.relationEditDialog.form = {
        sourceNodeId: sourceId,
        targetNodeId: targetId,
        relationLabel: link.label || "",
        originalSourceId: sourceId,
        originalTargetId: targetId,
      };
      this.currentEditRelation = link;
    },

    // 关系抽屉关闭处理
    _handleRelationDrawerClose() {
      this.relationEditDialog.visible = false;
      this._resetRelationDialogForm();
    },

    // 关系抽屉确认处理
    _handleRelationDrawerConfirm() {
      if (this._validateRelationForm()) {
        this._handleEditRelationConfirm();
      }
    },

    // 处理关系编辑确认
    _handleEditRelationConfirm() {
      const form = this.relationEditDialog.form;

      try {
        // 如果源节点和目标节点发生了变化，需要删除原关系，新增新关系
        const sourceChanged = form.sourceNodeId !== form.originalSourceId;
        const targetChanged = form.targetNodeId !== form.originalTargetId;

        if (sourceChanged || targetChanged) {
          // 删除原关系
          this.removeRelation(form.originalSourceId, form.originalTargetId);

          // 添加新关系
          const result = this.addRelation({
            source: form.sourceNodeId,
            target: form.targetNodeId,
            label: form.relationLabel,
            isHierarchy:
              this.relationTypeMap.get(form.relationLabel)?.isHierarchy ||
              false,
          });

          if (result) {
            this.$message?.success("关系更新成功");
            this.relationEditDialog.visible = false;
            this._resetRelationDialogForm();

            // 发送事件通知
            this.$emit("relation-edited", {
              oldRelation: {
                source: form.originalSourceId,
                target: form.originalTargetId,
              },
              newRelation: result,
            });
          } else {
            this.$message?.error("关系更新失败");
          }
        } else {
          // 只更新关系属性
          const result = this.updateRelation({
            source: form.sourceNodeId,
            target: form.targetNodeId,
            label: form.relationLabel,
            isHierarchy:
              this.relationTypeMap.get(form.relationLabel)?.isHierarchy ||
              false,
          });

          if (result) {
            this.$message?.success("关系更新成功");
            this.relationEditDialog.visible = false;
            this._resetRelationDialogForm();

            // 发送事件通知
            this.$emit("relation-edited", {
              relation: {
                source: form.sourceNodeId,
                target: form.targetNodeId,
                label: form.relationLabel,
              },
            });
          } else {
            this.$message?.error("关系更新失败");
          }
        }
      } catch (error) {
        console.error("编辑关系时发生错误:", error);
        this.$message?.error("编辑关系时发生错误: " + error.message);
      }
    },

    // 重置关系弹框表单
    _resetRelationDialogForm() {
      this.relationEditDialog.form = {
        sourceNodeId: "",
        targetNodeId: "",
        relationLabel: "",
        originalSourceId: "",
        originalTargetId: "",
      };
      this.currentEditRelation = null;
    },

    // 关系表单验证
    _validateRelationForm() {
      const form = this.relationEditDialog.form;

      // 验证源节点和目标节点
      if (!form.sourceNodeId || !form.targetNodeId) {
        this.$message?.error("请确保源节点和目标节点都已选择");
        return false;
      }

      // 检查源节点和目标节点是否相同
      if (form.sourceNodeId === form.targetNodeId) {
        this.$message?.error("源节点和目标节点不能相同");
        return false;
      }

      // 检查节点是否存在 - 使用nodeMap优化
      const sourceNode = this._getNodeById(form.sourceNodeId);
      const targetNode = this._getNodeById(form.targetNodeId);

      if (!sourceNode) {
        this.$message?.error("源节点不存在");
        return false;
      }
      if (!targetNode) {
        this.$message?.error("目标节点不存在");
        return false;
      }

      // 验证关系类型
      if (form.relationLabel && !this.relationTypeMap.has(form.relationLabel)) {
        this.$message?.error("选择的关系类型无效");
        return false;
      }

      // 如果节点关系发生了变化，检查新关系是否已存在
      const sourceChanged = form.sourceNodeId !== form.originalSourceId;
      const targetChanged = form.targetNodeId !== form.originalTargetId;

      if (sourceChanged || targetChanged) {
        const existingLink = this.links.find((link) => {
          const linkSourceId = link.source.id || link.source;
          const linkTargetId = link.target.id || link.target;
          return (
            linkSourceId === form.sourceNodeId &&
            linkTargetId === form.targetNodeId
          );
        });

        if (existingLink) {
          this.$message?.error("该关系已存在");
          return false;
        }
      }

      return true;
    },

    // 交换源节点和目标节点
    _switchRelationNodes() {
      const form = this.relationEditDialog.form;
      const temp = form.sourceNodeId;
      form.sourceNodeId = form.targetNodeId;
      form.targetNodeId = temp;
    },

    // 获取源节点名称 - 使用nodeMap优化
    _getSourceNodeName() {
      const sourceId = this.relationEditDialog.form.sourceNodeId;
      const sourceNode = this._getNodeById(sourceId);
      return sourceNode ? sourceNode.label : "未知节点";
    },

    // 获取目标节点名称
    _getTargetNodeName() {
      const targetId = this.relationEditDialog.form.targetNodeId;
      const targetNode = this.nodes.find((n) => n.id === targetId);
      return targetNode ? targetNode.label : "未知节点";
    },

    // 获取源节点类型 - 使用nodeMap优化
    _getSourceNodeType() {
      const sourceId = this.relationEditDialog.form.sourceNodeId;
      const sourceNode = this._getNodeById(sourceId);
      if (!sourceNode) return "未知类型";
      const nodeType = this.nodeTypeMap.get(sourceNode.type);
      return nodeType
        ? nodeType.label || nodeType.name
        : sourceNode.type || "未知类型";
    },

    // 获取目标节点类型 - 使用nodeMap优化
    _getTargetNodeType() {
      const targetId = this.relationEditDialog.form.targetNodeId;
      const targetNode = this._getNodeById(targetId);
      if (!targetNode) return "未知类型";
      const nodeType = this.nodeTypeMap.get(targetNode.type);
      return nodeType
        ? nodeType.label || nodeType.name
        : targetNode.type || "未知类型";
    },

    // ======= 公共API方法 =======

    // API 1: 高亮指定节点（可传入多个节点ID）
    highlightNodes(nodeIds = []) {
      // 清除之前的高亮
      this._clearHighlight();

      if (!Array.isArray(nodeIds) || nodeIds.length === 0) {
        return;
      }

      const nodeIdSet = new Set(nodeIds);

      // 获取高亮的节点
      const highlightedNodes = this.nodes.filter((node) =>
        nodeIdSet.has(node.id)
      );

      // 高亮指定的节点
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => nodeIdSet.has(d.id))
        .classed("dimmed", (d) => !nodeIdSet.has(d.id));

      // 高亮指定节点的标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => nodeIdSet.has(d.id))
        .classed("dimmed", (d) => !nodeIdSet.has(d.id));

      // 连接线和连接标签保持默认状态（不高亮）
      this.zoomGroup.selectAll(".link, .link-label").classed("dimmed", true);

      // 将高亮节点移动到画布中央
      if (highlightedNodes.length > 0) {
        this._centerToNodes(highlightedNodes);
      }
    },

    // API 2: 高亮指定节点及其直接相关节点和连线 - 优化版本
    highlightNodesWithRelations(nodeIds = []) {
      // 清除之前的高亮
      this._clearHighlight();

      if (!Array.isArray(nodeIds) || nodeIds.length === 0) {
        return;
      }

      const inputNodeIds = new Set(nodeIds);
      const connectedNodeIds = new Set(nodeIds);

      // 使用预计算的邻居表，避免遍历所有连线
      nodeIds.forEach((nodeId) => {
        const neighbors = this.nodeNeighbors.get(nodeId);
        if (neighbors) {
          neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
        }
      });

      // 高亮节点（包括指定节点和相关节点）
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 高亮相关连接线
      this.zoomGroup
        .selectAll(".link")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(inputNodeIds.has(sourceId) || inputNodeIds.has(targetId));
        })
        .attr("marker-end", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          const isConnected =
            inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
          if (d.isHierarchy === true) {
            return isConnected
              ? "url(#arrowhead-highlight)"
              : "url(#arrowhead)";
          } else {
            return "none";
          }
        });

      // 高亮相关连接标签
      this.zoomGroup
        .selectAll(".link-label")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return inputNodeIds.has(sourceId) || inputNodeIds.has(targetId);
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(inputNodeIds.has(sourceId) || inputNodeIds.has(targetId));
        });

      // 高亮节点标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 将相关节点移动到画布中央
      const relatedNodes = this.nodes.filter((node) =>
        connectedNodeIds.has(node.id)
      );
      if (relatedNodes.length > 0) {
        this._centerToNodes(relatedNodes);
      }
    },

    // API 3: 高亮指定关系类型的节点和连线（根据links的label）
    highlightRelationsByLabel(relationLabels = []) {
      // 清除之前的高亮
      this._clearHighlight();

      if (!Array.isArray(relationLabels) || relationLabels.length === 0) {
        return;
      }

      const relationLabelSet = new Set(relationLabels);
      const connectedNodeIds = new Set();

      // 找到匹配指定关系标签的连接
      const matchingLinks = this.links.filter((link) => {
        return link.label && relationLabelSet.has(link.label);
      });

      // 收集所有相关节点ID
      matchingLinks.forEach((link) => {
        const sourceId = link.source.id || link.source;
        const targetId = link.target.id || link.target;
        connectedNodeIds.add(sourceId);
        connectedNodeIds.add(targetId);
      });

      if (connectedNodeIds.size === 0) {
        console.warn(`未找到标签为 [${relationLabels.join(", ")}] 的关系`);
        return;
      }

      // 高亮相关节点
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 高亮匹配的连接线
      this.zoomGroup
        .selectAll(".link")
        .classed("highlighted", (d) => {
          return d.label && relationLabelSet.has(d.label);
        })
        .classed("dimmed", (d) => {
          return !(d.label && relationLabelSet.has(d.label));
        })
        .attr("marker-end", (d) => {
          const isMatching = d.label && relationLabelSet.has(d.label);
          if (d.isHierarchy === true) {
            return isMatching ? "url(#arrowhead-highlight)" : "url(#arrowhead)";
          } else {
            return "none";
          }
        });

      // 高亮匹配的连接标签
      this.zoomGroup
        .selectAll(".link-label")
        .classed("highlighted", (d) => {
          return d.label && relationLabelSet.has(d.label);
        })
        .classed("dimmed", (d) => {
          return !(d.label && relationLabelSet.has(d.label));
        });

      // 高亮相关节点标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 将相关节点移动到画布中央
      const relationNodes = this.nodes.filter((node) =>
        connectedNodeIds.has(node.id)
      );
      if (relationNodes.length > 0) {
        this._centerToNodes(relationNodes);
      }
    },

    // API 4: 按节点类型高亮指定节点（可传入多个类型）
    highlightNodesByType(nodeTypes = []) {
      // 清除之前的高亮
      this._clearHighlight();

      if (!Array.isArray(nodeTypes) || nodeTypes.length === 0) {
        return;
      }

      const nodeTypeSet = new Set(nodeTypes);

      // 获取匹配类型的节点
      const matchingNodes = this.nodes.filter(
        (node) => node.type && nodeTypeSet.has(node.type)
      );

      if (matchingNodes.length === 0) {
        console.warn(`未找到类型为 [${nodeTypes.join(", ")}] 的节点`);
        return;
      }

      // 高亮匹配类型的节点
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => d.type && nodeTypeSet.has(d.type))
        .classed("dimmed", (d) => !(d.type && nodeTypeSet.has(d.type)));

      // 高亮匹配类型节点的标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => d.type && nodeTypeSet.has(d.type))
        .classed("dimmed", (d) => !(d.type && nodeTypeSet.has(d.type)));

      // 连接线和连接标签保持默认状态（不高亮）
      this.zoomGroup.selectAll(".link, .link-label").classed("dimmed", true);

      // 将匹配类型的节点移动到画布中央
      if (matchingNodes.length > 0) {
        this._centerToNodes(matchingNodes);
      }
    },

    // API 5: 按节点类型高亮节点及其关系网络 - 优化版本
    highlightNodesByTypeWithRelations(nodeTypes = []) {
      // 清除之前的高亮
      this._clearHighlight();

      if (!Array.isArray(nodeTypes) || nodeTypes.length === 0) {
        return;
      }

      const nodeTypeSet = new Set(nodeTypes);

      // 找到匹配类型的节点ID
      const matchingNodeIds = new Set();
      this.nodes.forEach((node) => {
        if (node.type && nodeTypeSet.has(node.type)) {
          matchingNodeIds.add(node.id);
        }
      });

      if (matchingNodeIds.size === 0) {
        console.warn(`未找到类型为 [${nodeTypes.join(", ")}] 的节点`);
        return;
      }

      // 使用预计算的邻居表，避免遍历所有连线
      const connectedNodeIds = new Set(matchingNodeIds);
      matchingNodeIds.forEach((nodeId) => {
        const neighbors = this.nodeNeighbors.get(nodeId);
        if (neighbors) {
          neighbors.forEach((neighborId) => connectedNodeIds.add(neighborId));
        }
      });

      // 高亮节点（包括指定类型节点和相关节点）
      this.zoomGroup
        .selectAll(".node-group")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 高亮相关连接线
      this.zoomGroup
        .selectAll(".link")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(
            matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId)
          );
        })
        .attr("marker-end", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          const isConnected =
            matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
          if (d.isHierarchy === true) {
            return isConnected
              ? "url(#arrowhead-highlight)"
              : "url(#arrowhead)";
          } else {
            return "none";
          }
        });

      // 高亮相关连接标签
      this.zoomGroup
        .selectAll(".link-label")
        .classed("highlighted", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId);
        })
        .classed("dimmed", (d) => {
          const sourceId = d.source.id || d.source;
          const targetId = d.target.id || d.target;
          return !(
            matchingNodeIds.has(sourceId) || matchingNodeIds.has(targetId)
          );
        });

      // 高亮节点标签
      this.zoomGroup
        .selectAll(".node-label")
        .classed("highlighted", (d) => connectedNodeIds.has(d.id))
        .classed("dimmed", (d) => !connectedNodeIds.has(d.id));

      // 将相关节点移动到画布中央
      const relatedNodes = this.nodes.filter((node) =>
        connectedNodeIds.has(node.id)
      );
      if (relatedNodes.length > 0) {
        this._centerToNodes(relatedNodes);
      }
    },

    // 清除所有高亮状态（公共API）
    clearAllHighlight() {
      this._clearHighlight();
    },

    // 添加节点 - 添加缓存更新
    addNode(node, relationList = []) {
      // 验证节点数据
      if (!node.id || !node.label) {
        this.$message.error("节点必须有 id and label 属性");
        return;
      }

      // 检查ID是否已存在 - 使用nodeMap优化
      if (this._getNodeById(node.id)) {
        this.$message.error("节点 id 已经存在了", node.id);
        return;
      }
      // 创建新节点
      const newNode = {
        ...node,
        color:
          node.color ||
          this.nodeTypeMap.get(node.type).color ||
          this.defaultNodeStyle.color,
        size:
          node.size ||
          this.nodeTypeMap.get(node.type).size ||
          this.defaultNodeStyle.size,
        x: Math.random() * this.width,
        y: Math.random() * this.height,
        vx: 0,
        vy: 0,
      };

      // 添加节点
      this.nodes.push(newNode);
      // 更新nodeMap缓存
      this._updateNodeInMap(newNode);

      // 添加连接（支持字符串或对象格式）
      relationList.forEach((relation) => {
        let sourceId, targetId, linkData;

        if (typeof relation === "string") {
          // 兼容原有格式：简单的目标节点ID字符串
          sourceId = relation;
          linkData = {
            source: sourceId,
            target: node.id,
            // 默认连接属性
            label: "",
            isHierarchy: false,
          };
        } else if (
          typeof relation === "object" &&
          (relation.source || relation.target)
        ) {
          // 新格式：完整的连接对象
          sourceId = relation.source || node.id;
          targetId = relation.target || node.id;

          linkData = {
            source: sourceId,
            target: targetId,
            label: relation.label || "",
            isHierarchy:
              relation.isHierarchy ||
              this.relationTypeMap.get(relation.label).isHierarchy ||
              false,
            // 支持其他自定义属性
            ...relation,
          };
          // 确保正确的 source 和 target 属性
          linkData.source = sourceId;
          linkData.target = targetId;
        } else {
          console.warn("无效的连接格式:", relation);
          return;
        }

        // 验证连接数据的完整性
        if (!linkData.source || !linkData.target) {
          this.$message.error("连接数据无效:", linkData);
          return;
        }

        // 检查目标节点是否存在 - 使用nodeMap优化
        const sourceNode = this._getNodeById(sourceId);
        if (sourceNode) {
          this.links.push(linkData);
        } else {
          console.warn(`目标节点不存在: ${sourceId}`);
        }
      });

      // 重新预处理数据和缓存
      this._preprocessLinkData();

      // 更新图形
      this._updateSimulation();
      this._renderGraph();

      return newNode;
    },

    // 编辑节点（可能包含节点关系）- 全量操作模式
    editNode(nodeId, updates, updatedRelationList = null) {
      const nodeIndex = this.nodes.findIndex((n) => n.id === nodeId);
      // 也可以优化为： const targetNode = this._getNodeById(nodeId); if (!targetNode) return false;
      if (nodeIndex === -1) {
        this.$message.error("节点没有找到");
        return false;
      }

      // 更新节点数据（排除连接相关的更新）
      if (Object.keys(updates).length > 0) {
        Object.assign(this.nodes[nodeIndex], updates);
      }

      // 全量更新连接关系（如果提供了updatedRelationList参数）
      if (updatedRelationList && Array.isArray(updatedRelationList)) {
        // 1. 找到所有与该节点相关的现有连接
        const currentRelatedLinks = this.links.filter((link) => {
          const sourceId = link.source.id || link.source;
          const targetId = link.target.id || link.target;
          return sourceId === nodeId || targetId === nodeId;
        });

        // 2. 创建传入连接的标识集合，用于快速查找
        const incomingRelationListSet = new Set();
        const validUpdatedRelationList = [];

        updatedRelationList.forEach((connUpdate, index) => {
          const { target, source, ...linkUpdates } = connUpdate;

          // 确定实际的源节点和目标节点ID
          let actualSourceId, actualTargetId;

          if (target && source) {
            // 指定了源和目标
            actualSourceId = source;
            actualTargetId = target;
          } else if (target) {
            // 只指定了目标，当前节点作为源
            actualSourceId = nodeId;
            actualTargetId = target;
          } else if (source) {
            // 只指定了源，当前节点作为目标
            actualSourceId = source;
            actualTargetId = nodeId;
          } else {
            console.warn(`跳过无效的连接更新（索引${index}）:`, connUpdate);
            return;
          }

          // 验证节点存在性
          const sourceExists = this.nodes.find((n) => n.id === actualSourceId);
          const targetExists = this.nodes.find((n) => n.id === actualTargetId);

          if (!sourceExists || !targetExists) {
            console.warn(
              `跳过连接更新（索引${index}）- 节点不存在: source=${actualSourceId}, target=${actualTargetId}`
            );
            return;
          }

          // 创建连接标识
          const relationKey = `${actualSourceId}->${actualTargetId}`;
          incomingRelationListSet.add(relationKey);

          validUpdatedRelationList.push({
            sourceId: actualSourceId,
            targetId: actualTargetId,
            updates: linkUpdates,
            relationKey: relationKey,
          });
        });

        // 3. 删除现有关系中不在传入关系列表中的连接
        const linksToRemove = currentRelatedLinks.filter((link) => {
          const sourceId = link.source.id || link.source;
          const targetId = link.target.id || link.target;
          const relationKey = `${sourceId}->${targetId}`;
          return !incomingRelationListSet.has(relationKey);
        });

        linksToRemove.forEach((linkToRemove) => {
          const linkIndex = this.links.findIndex((l) => l === linkToRemove);
          if (linkIndex !== -1) {
            const sourceId = linkToRemove.source.id || linkToRemove.source;
            const targetId = linkToRemove.target.id || linkToRemove.target;
            this.links.splice(linkIndex, 1);
            console.log(`删除关系: ${sourceId} → ${targetId}`);
          }
        });

        // 4. 新增或更新传入的连接关系
        validUpdatedRelationList.forEach(
          ({ sourceId, targetId, updates, relationKey }) => {
            // 查找现有连接
            const existingLinkIndex = this.links.findIndex((link) => {
              const linkSourceId = link.source.id || link.source;
              const linkTargetId = link.target.id || link.target;
              return linkSourceId === sourceId && linkTargetId === targetId;
            });

            if (existingLinkIndex !== -1) {
              // 更新现有连接
              const originalLink = { ...this.links[existingLinkIndex] };
              Object.assign(this.links[existingLinkIndex], updates);

              // 确保 source 和 target 不被意外修改
              this.links[existingLinkIndex].source = originalLink.source;
              this.links[existingLinkIndex].target = originalLink.target;

              console.log(`更新关系: ${sourceId} → ${targetId}`, updates);
            } else {
              // 新增连接
              const newLink = {
                source: sourceId,
                target: targetId,
                label: updates.label || "",
                isHierarchy:
                  updates.isHierarchy ||
                  this.relationTypeMap.get(updates.label).isHierarchy ||
                  false,
                ...updates,
              };

              this.links.push(newLink);
              console.log(`新增关系: ${sourceId} → ${targetId}`, newLink);
            }
          }
        );

        // 5. 重新预处理数据和缓存
        this._preprocessLinkData();

        // 6. 更新模拟
        this._updateSimulation();
      }

      // 重新渲染
      this._renderGraph();

      return true;
    },

    // 移除节点 - 添加缓存更新
    removeNodeById(nodeId) {
      // 移除节点
      this.nodes = this.nodes.filter((n) => n.id !== nodeId);
      // 从 nodeMap 中删除
      this._removeNodeFromMap(nodeId);

      // 移除相关连接
      this.links = this.links.filter(
        (l) =>
          (l.source.id || l.source) !== nodeId &&
          (l.target.id || l.target) !== nodeId
      );

      // 清除焦点状态
      if (this.focusedNode?.id === nodeId) {
        this._unfocus();
      }

      // 重新预处理数据和缓存
      this._preprocessLinkData();

      // 更新图形
      this._updateSimulation();
      this._renderGraph();

      return true;
    },

    // 更新节点关系（支持单个关系和批量关系）
    updateRelation(relationData) {
      // 验证输入参数
      if (!relationData) {
        this.$message.error("更新关系需要提供关系数据");
        return false;
      }

      // 判断是单个关系还是关系数组
      const relations = Array.isArray(relationData)
        ? relationData
        : [relationData];

      if (relations.length === 0) {
        this.$message.error("关系数组不能为空");
        return false;
      }

      const results = {
        updated: [],
        added: [],
        failed: [],
        total: relations.length,
      };

      relations.forEach((relationUpdate, index) => {
        try {
          // 验证单个关系数据
          if (!relationUpdate || typeof relationUpdate !== "object") {
            results.failed.push({
              index,
              relation: relationUpdate,
              error: "关系数据必须是对象格式",
            });
            return;
          }

          const { source, target, ...updates } = relationUpdate;

          // 必须提供源节点和目标节点ID
          if (!source || !target) {
            results.failed.push({
              index,
              relation: relationUpdate,
              error: "必须提供 source 和 target 节点ID",
            });
            return;
          }

          // 检查源节点和目标节点是否存在 - 使用nodeMap优化
          const sourceNode = this._getNodeById(source);
          const targetNode = this._getNodeById(target);

          if (!sourceNode) {
            results.failed.push({
              index,
              relation: relationUpdate,
              error: `源节点 ${source} 不存在`,
            });
            return;
          }

          if (!targetNode) {
            results.failed.push({
              index,
              relation: relationUpdate,
              error: `目标节点 ${target} 不存在`,
            });
            return;
          }

          // 查找对应的关系
          const linkIndex = this.links.findIndex((link) => {
            const linkSourceId = link.source.id || link.source;
            const linkTargetId = link.target.id || link.target;
            return linkSourceId === source && linkTargetId === target;
          });

          if (linkIndex !== -1) {
            // 关系存在，进行更新
            const originalLink = { ...this.links[linkIndex] };
            Object.assign(this.links[linkIndex], updates);

            // 确保 source 和 target 不被意外修改
            this.links[linkIndex].source = originalLink.source;
            this.links[linkIndex].target = originalLink.target;

            results.updated.push({
              index,
              relation: { source, target, ...updates },
              originalData: originalLink,
            });

            console.log(`成功更新关系: ${source} → ${target}`, updates);
          } else {
            // 关系不存在，进行添加（复用 addRelation 的逻辑）
            const newLink = {
              source: source,
              target: target,
              label: updates.label || "",
              isHierarchy:
                updates.isHierarchy ||
                this.relationTypeMap.get(updates.label).isHierarchy ||
                false,
              ...updates,
            };

            this.links.push(newLink);

            results.added.push({
              index,
              relation: newLink,
            });

            console.log(`成功新增关系: ${source} → ${target}`, newLink);
          }
        } catch (error) {
          results.failed.push({
            index,
            relation: relationUpdate,
            error: error.message || "处理关系时发生未知错误",
          });
        }
      });

      // 只有在有成功操作时才更新图形
      if (results.updated.length > 0 || results.added.length > 0) {
        // 重新预处理数据和缓存
        this._preprocessLinkData();

        // 更新模拟和渲染
        this._updateSimulation();
        this._renderGraph();
      }

      // 输出操作汇总
      if (results.updated.length > 0) {
        console.log(`批量更新完成: 更新了 ${results.updated.length} 个关系`);
      }
      if (results.added.length > 0) {
        console.log(`批量添加完成: 新增了 ${results.added.length} 个关系`);
      }
      if (results.failed.length > 0) {
        console.warn(
          `批量操作中有 ${results.failed.length} 个关系处理失败:`,
          results.failed
        );
      }

      // 如果是单个关系，返回简化的结果
      if (!Array.isArray(relationData)) {
        if (results.failed.length > 0) {
          return false;
        }
        return results.updated.length > 0 ? "updated" : "added";
      }

      // 批量操作返回详细结果
      return {
        success: results.updated.length > 0 || results.added.length > 0,
        ...results,
      };
    },

    // 新增节点关系（支持单个和批量添加）
    addRelation(relationData) {
      // 验证输入参数
      if (!relationData) {
        this.$message.error("新增关系需要提供关系数据");
        return false;
      }

      // 判断是单个关系还是关系数组
      const relations = Array.isArray(relationData)
        ? relationData
        : [relationData];

      if (relations.length === 0) {
        this.$message.error("关系数组不能为空");
        return false;
      }

      const results = {
        added: [],
        failed: [],
        skipped: [], // 已存在的关系
        total: relations.length,
      };

      relations.forEach((relation, index) => {
        try {
          // 验证单个关系数据
          if (!relation || typeof relation !== "object") {
            results.failed.push({
              index,
              relation,
              error: "关系数据必须是对象格式",
            });
            return;
          }

          const { source, target, ...linkAttributes } = relation;

          // 必须提供源节点和目标节点ID
          if (!source || !target) {
            results.failed.push({
              index,
              relation,
              error: "新增关系必须提供 source 和 target 节点ID",
            });
            return;
          }

          // 检查源节点和目标节点是否存在 - 使用nodeMap优化
          const sourceNode = this._getNodeById(source);
          const targetNode = this._getNodeById(target);

          if (!sourceNode) {
            results.failed.push({
              index,
              relation,
              error: `源节点 ${source} 不存在`,
            });
            return;
          }

          if (!targetNode) {
            results.failed.push({
              index,
              relation,
              error: `目标节点 ${target} 不存在`,
            });
            return;
          }

          // 检查关系是否已存在
          const existingLink = this.links.find((link) => {
            const linkSourceId = link.source.id || link.source;
            const linkTargetId = link.target.id || link.target;
            return linkSourceId === source && linkTargetId === target;
          });

          if (existingLink) {
            results.skipped.push({
              index,
              relation,
              existingRelation: existingLink,
              reason: `从节点 ${source} 到节点 ${target} 的关系已存在`,
            });
            return;
          }

          // 创建新的关系对象
          const newLink = {
            source: source,
            target: target,
            label: linkAttributes.label || "",
            isHierarchy:
              linkAttributes.isHierarchy ||
              this.relationTypeMap.get(linkAttributes.label).isHierarchy ||
              false,
            ...linkAttributes,
          };

          // 添加到连接列表
          this.links.push(newLink);

          results.added.push({
            index,
            relation: newLink,
          });

          console.log(`成功新增关系: ${source} → ${target}`, newLink);
        } catch (error) {
          results.failed.push({
            index,
            relation,
            error: error.message || "处理关系时发生未知错误",
          });
        }
      });

      // 只有在有成功添加时才更新图形
      if (results.added.length > 0) {
        // 重新预处理数据和缓存
        this._preprocessLinkData();

        // 更新模拟和渲染
        this._updateSimulation();
        this._renderGraph();
      }

      // 输出操作汇总
      if (results.added.length > 0) {
        console.log(`批量添加完成: 新增了 ${results.added.length} 个关系`);
      }
      if (results.skipped.length > 0) {
        console.log(
          `批量添加中跳过了 ${results.skipped.length} 个已存在的关系`
        );
      }
      if (results.failed.length > 0) {
        console.warn(
          `批量添加中有 ${results.failed.length} 个关系处理失败:`,
          results.failed
        );
      }

      // 如果是单个关系，返回简化的结果
      if (!Array.isArray(relationData)) {
        if (results.failed.length > 0) {
          // 单个操作失败，显示错误消息
          const error = results.failed[0];
          this.$message.error(error.error);
          return false;
        }
        if (results.skipped.length > 0) {
          // 单个操作被跳过（关系已存在）
          const skipped = results.skipped[0];
          this.$message.warning(skipped.reason);
          return null; // 返回 null 表示关系已存在，未添加
        }
        if (results.added.length > 0) {
          // 单个操作成功
          return results.added[0].relation;
        }
        return false;
      }

      // 批量操作返回详细结果
      return {
        success: results.added.length > 0,
        ...results,
      };
    },

    // 删除节点关系
    removeRelation(source, target) {
      // 验证输入参数
      if (!source || !target) {
        this.$message.error("删除关系必须提供 source 和 target 节点ID");
        return false;
      }

      // 查找对应的关系
      const linkIndex = this.links.findIndex((link) => {
        const linkSourceId = link.source.id || link.source;
        const linkTargetId = link.target.id || link.target;
        return linkSourceId === source && linkTargetId === target;
      });

      if (linkIndex === -1) {
        this.$message.error(`未找到从节点 ${source} 到节点 ${target} 的关系`);
        return false;
      }

      // 获取要删除的关系信息（用于日志）
      const deletedLink = { ...this.links[linkIndex] };

      // 从连接列表中删除
      this.links.splice(linkIndex, 1);

      // 重新预处理数据和缓存
      this._preprocessLinkData();

      // 更新模拟和渲染
      this._updateSimulation();
      this._renderGraph();

      console.log(`成功删除关系: ${source} → ${target}`, deletedLink);
      return true;
    },

    // 批量删除节点关系（支持删除多个关系）
    removeRelations(relationPairs) {
      // 验证输入参数
      if (!Array.isArray(relationPairs) || relationPairs.length === 0) {
        this.$message.error("批量删除关系需要提供关系对数组");
        return false;
      }

      let deletedCount = 0;
      const deletedRelations = [];

      relationPairs.forEach(({ source, target }) => {
        if (!source || !target) {
          console.warn(`跳过无效的关系对: source=${source}, target=${target}`);
          return;
        }

        // 查找对应的关系
        const linkIndex = this.links.findIndex((link) => {
          const linkSourceId = link.source.id || link.source;
          const linkTargetId = link.target.id || link.target;
          return linkSourceId === source && linkTargetId === target;
        });

        if (linkIndex !== -1) {
          const deletedLink = { ...this.links[linkIndex] };
          this.links.splice(linkIndex, 1);
          deletedRelations.push(deletedLink);
          deletedCount++;
        } else {
          console.warn(`未找到从节点 ${source} 到节点 ${target} 的关系`);
        }
      });

      if (deletedCount > 0) {
        // 重新预处理数据和缓存
        this._preprocessLinkData();

        // 更新模拟和渲染
        this._updateSimulation();
        this._renderGraph();

        console.log(`成功批量删除 ${deletedCount} 个关系`, deletedRelations);
      }

      return {
        success: deletedCount > 0,
        deletedCount: deletedCount,
        deletedRelations: deletedRelations,
      };
    },

    // 获取节点所有直接相关的关系 - 高性能优化版本
    getNodeRelations(nodeId) {
      // 验证节点是否存在 - 使用nodeMap优化
      const targetNode = this._getNodeById(nodeId);
      if (!targetNode) {
        console.warn(`节点 ${nodeId} 不存在`);
        return null;
      }

      // 使用预处理的有效连线，提高性能
      const relatedLinks = this.validLinks.filter((link) => {
        const sourceId = link.source.id || link.source;
        const targetId = link.target.id || link.target;
        return sourceId === nodeId || targetId === nodeId;
      });

      // 使用邻居缓存获取相关节点ID
      const relatedNodeIds = this.nodeNeighbors.get(nodeId) || new Set();

      // 预构建节点ID到节点对象的映射，避免重复查找
      const nodeMap = new Map();
      relatedNodeIds.forEach((id) => {
        const node = this.nodes.find((n) => n.id === id);
        if (node) nodeMap.set(id, node);
      });
      nodeMap.set(nodeId, targetNode); // 添加目标节点自身

      // 获取相关节点的完整信息
      const relatedNodes = Array.from(nodeMap.values()).filter(
        (node) => node.id !== nodeId
      );

      // 构建关系信息，包含方向性 - 性能优化版本
      const relationships = relatedLinks.map((link) => {
        const sourceId = link.source.id || link.source;
        const targetId = link.target.id || link.target;

        // 使用预构建的映射避免重复查找
        const sourceNode = nodeMap.get(sourceId);
        const targetNodeInLink = nodeMap.get(targetId);

        // 预计算isHierarchy，避免重复Map查找
        const relationType = this.relationTypeMap.get(link.label);
        const isHierarchy =
          link.isHierarchy || relationType?.isHierarchy || false;

        return {
          // 连接信息
          link: {
            source: sourceId,
            target: targetId,
            label: link.label || "",
            isHierarchy: isHierarchy,
          },
          // 关系方向（相对于查询节点）
          direction: sourceId === nodeId ? "outgoing" : "incoming",
          // 对方节点信息
          relatedNode: sourceId === nodeId ? targetNodeInLink : sourceNode,
          // 延迟计算关系描述（仅在需要时计算）
          get relationDescription() {
            return sourceId === nodeId
              ? `${targetNode.label} → ${targetNodeInLink?.label || "未知节点"}`
              : `${sourceNode?.label || "未知节点"} → ${targetNode.label}`;
          },
        };
      });

      return {
        // 目标节点信息
        targetNode: targetNode,
        // 相关节点列表
        relatedNodes: relatedNodes,
        // 相关连接列表
        relatedLinks: relatedLinks,
        // 详细关系信息（包含方向）
        relationships: relationships,
        // 统计信息
        statistics: {
          totalRelations: relatedLinks.length,
          incomingRelations: relationships.filter(
            (r) => r.direction === "incoming"
          ).length,
          outgoingRelations: relationships.filter(
            (r) => r.direction === "outgoing"
          ).length,
          hierarchyRelations: relatedLinks.filter((l) => l.isHierarchy === true)
            .length,
          cooperationRelations: relatedLinks.filter(
            (l) => l.isHierarchy === false
          ).length,
        },
      };
    },

    // 设置事件监听
    _setupEventListeners() {
      document.addEventListener("click", this.handleDocumentClick);
    },

    // 移除事件监听
    _removeEventListeners() {
      document.removeEventListener("click", this.handleDocumentClick);
    },

    // 文档点击处理
    handleDocumentClick(event) {
      if (!this.$refs.container.contains(event.target)) {
        this._hideContextMenu();
      }
    },
  },
};
</script>

<style scoped lang="scss">
.network-graph-container {
  position: relative;
  width: 100%;
  height: 100%;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

.network-svg {
  width: 100%;
  height: 100%;
  cursor: grab;
  display: block;
}
.network-svg:active {
  cursor: grabbing;
}

/* 连接线样式 */
:deep(.link) {
  opacity: 1;
  stroke: #ccc;
  stroke-width: 1px;
  transition: all 0.3s ease;
}
:deep(.link.highlighted) {
  stroke: #4a90e2;
}
:deep(.link.dimmed) {
  opacity: 0.3;
}
:deep(.link.hover-highlighted) {
  stroke: #4a90e2;
}
:deep(.link.hover-dimmed) {
  opacity: 0.3;
}

/* 连接标签样式 */
:deep(.link-label) {
  font-family: "Alibaba PuHuiTi", "Arial", sans-serif;
  user-select: none;
  fill: #333;
  text-anchor: middle;
  dominant-baseline: central;
  font-size: 10px;
  font-weight: 700;
  pointer-events: none;
  text-shadow: 1px 1px 2px rgba(255, 255, 255, 0.8);
  transition: all 0.3s ease;
}
:deep(.link-label.highlighted) {
  fill: #4a90e2;
}
:deep(.link-label.dimmed) {
  opacity: 0.3;
}
:deep(.link-label.hover-highlighted) {
  fill: #4a90e2;
}
:deep(.link-label.hover-dimmed) {
  opacity: 0.3;
}

/* 编辑模式下的连线标签 */
:deep(.link-label.editable) {
  pointer-events: all;
  cursor: pointer;
}
:deep(.link-label.editable:hover) {
  fill: #409eff;
  font-weight: 800;
}

/* 节点标签样式 */
:deep(.node-label) {
  font-family: "Alibaba PuHuiTi", "Arial", sans-serif;
  user-select: none;
  fill: #999;
  text-anchor: middle;
  dominant-baseline: central;
  font-size: 10px;
  font-weight: 400;
  pointer-events: none;
  transition: all 0.3s ease;
}
:deep(.node-label.highlighted) {
  fill: #666;
}
:deep(.node-label.dimmed) {
  opacity: 0.3;
}
:deep(.node-label.hover-highlighted) {
  fill: #666;
}
:deep(.node-label.hover-dimmed) {
  opacity: 0.3;
}

/* 编辑模式下的节点标签 */
:deep(.node-label.editable) {
  pointer-events: all;
  cursor: pointer;
}

:deep(.node-label.editable:hover) {
  fill: #409eff;
  font-weight: 500;
}

/* 节点样式 */
:deep(.node-group) {
  cursor: pointer;
  transition: all 0.3s ease;
}
:deep(.node-circle) {
  transition: all 0.3s ease;
}
:deep(.node-group.highlighted .node-circle) {
  stroke: #fff;
  stroke-width: 3px;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 1));
}
:deep(.node-group.dimmed) {
  opacity: 0.3;
}
:deep(.node-group.hover-highlighted .node-circle) {
  stroke: #fff;
  stroke-width: 3px;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 1));
}
:deep(.node-group.hover-dimmed) {
  opacity: 0.3;
}

/* 右键菜单样式 */
.context-menu {
  position: absolute;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(10px);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  padding: 8px 0;
  min-width: 180px;
  z-index: 1000;
  border: 1px solid rgba(255, 255, 255, 0.3);
  animation: contextMenuFadeIn 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes contextMenuFadeIn {
  from {
    opacity: 0;
    transform: scale(0.9) translateY(-10px);
  }

  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.menu-item {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  cursor: pointer;
  transition: all 0.15s ease;
  font-size: 14px;
  color: #333;
  gap: 12px;
  .icon-add::before {
    content: "➕";
  }
  .icon-edit::before {
    content: "✏️";
  }
  .icon-delete::before {
    content: "🗑️";
  }
}

.menu-item:hover {
  background: rgba(52, 152, 219, 0.1);
  color: #3498db;
}
.menu-item.danger {
  color: #e74c3c;
}
.menu-item.danger:hover {
  background: rgba(231, 76, 60, 0.1);
  color: #c0392b;
}
.menu-separator {
  height: 1px;
  background: rgba(0, 0, 0, 0.1);
  margin: 4px 12px;
}

/* 节点编辑抽屉样式 */
.drawer-content {
  height: 100%;
  display: flex;
  flex-direction: column;

  .drawer-body {
    flex: 1;
    overflow-y: auto;
    padding: 20px;
  }

  .drawer-footer {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    padding: 16px 20px;
    border-top: 1px solid #e1e8ed;
    background: #f8fafc;
    flex-shrink: 0;
  }

  .form-section {
    margin-bottom: 32px;
    h4 {
      margin: 0 0 16px 0;
      font-size: 16px;
      font-weight: 600;
      color: #2d3748;
    }

    .empty-state {
      text-align: center;
      color: #718096;
      padding: 40px 20px;
      font-size: 14px;
      background: #f7fafc;
      border-radius: 8px;
      border: 2px dashed #e2e8f0;
    }
  }

  .form-section:last-child {
    margin-bottom: 0;
  }
  .section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
    h4 {
      margin: 0;
    }
  }

  .btn-add {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background: #4299e1;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    transition: all 0.2s ease;
  }

  .btn-add:hover {
    background: #3182ce;
    transform: translateY(-1px);
  }

  .btn-add .icon-add::before {
    content: "+";
    font-weight: bold;
  }

  .form-row {
    display: flex;
    gap: 16px;
    margin-bottom: 16px;

    .form-group {
      flex: 1;
    }

    .form-group.full-width {
      flex: 1;
    }

    .form-group label {
      display: block;
      margin-bottom: 6px;
      font-size: 14px;
      font-weight: 500;
      color: #4a5568;
    }

    .form-input,
    .form-select {
      width: 100%;
      padding: 10px 12px;
      border: 2px solid #e2e8f0;
      border-radius: 8px;
      font-size: 14px;
      transition: all 0.2s ease;
      background: white;
    }

    .form-input:focus,
    .form-select:focus {
      outline: none;
      border-color: #4299e1;
      box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
    }

    .direction-switch {
      display: flex;
      align-items: end;
      .btn-switch {
        background: #f7fafc;
        border: 2px solid #e2e8f0;
        border-radius: 8px;
        cursor: pointer;
        font-size: 16px;
        color: #4a5568;
        transition: all 0.2s ease;
        min-width: 40px;
        height: 32px;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .btn-switch:hover {
        background: #edf2f7;
        border-color: #cbd5e0;
        color: #2d3748;
      }
    }
  }
  .form-row:last-child {
    margin-bottom: 0;
  }
  .form-row.direction-row {
    align-items: end;
  }

  .relation-item {
    border: 2px solid #e2e8f0;
    border-radius: 12px;
    margin-bottom: 16px;
    background: #f9fafb;
    overflow: hidden;

    .relation-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 12px 16px;
      background: #f1f5f9;
      border-bottom: 1px solid #e2e8f0;
    }

    .relation-index {
      font-size: 14px;
      font-weight: 600;
      color: #4a5568;
    }

    .btn-remove {
      display: flex;
      align-items: center;
      gap: 4px;
      padding: 6px 10px;
      background: #fed7d7;
      color: #c53030;
      border: none;
      border-radius: 6px;
      cursor: pointer;
      font-size: 12px;
      font-weight: 500;
      transition: all 0.2s ease;
    }

    .btn-remove:hover {
      background: #feb2b2;
      color: #9b2c2c;
    }

    .btn-remove .icon-delete::before {
      content: "×";
      font-size: 14px;
      font-weight: bold;
    }

    .relation-form {
      padding: 16px;
    }

    /* 当前节点显示样式 */
    .current-node-display {
      display: flex;
      align-items: center;
      gap: 8px;
      height: 32px;
      padding: 4px 12px;
      background: #edf2f7;
      border: 2px solid #cbd5e0;
      border-radius: 6px;
      font-size: 14px;
    }

    .current-node-text {
      color: #2d3748;
      font-weight: 500;
    }

    .current-node-badge {
      background: #4299e1;
      color: white;
      padding: 2px 8px;
      border-radius: 12px;
      font-size: 12px;
      font-weight: 500;
    }
  }

  .relation-item:last-child {
    margin-bottom: 0;
  }

  /* 关系编辑特定样式 */
  .relation-direction-container {
    background: #f9fafb;
    border: 2px solid #e2e8f0;
    border-radius: 12px;
    padding: 20px;
    margin-top: 10px;

    .direction-row {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 16px;
    }

    .node-info {
      flex: 1;
      text-align: center;

      .node-label {
        font-size: 14px;
        font-weight: 600;
        color: #4a5568;
        margin-bottom: 8px;
      }

      .node-display {
        background: white;
        border: 2px solid #cbd5e0;
        border-radius: 8px;
        padding: 12px;
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);

        .node-name {
          display: block;
          font-size: 16px;
          font-weight: 600;
          color: #2d3748;
          margin-bottom: 4px;
        }

        .node-type {
          font-size: 12px;
          color: #718096;
          font-style: italic;
        }
      }
    }

    .source-node .node-display {
      border-color: #4299e1;
      background: linear-gradient(135deg, #e6f3ff 0%, #ffffff 100%);
    }

    .target-node .node-display {
      border-color: #48bb78;
      background: linear-gradient(135deg, #f0fff4 0%, #ffffff 100%);
    }

    .direction-arrow {
      position: relative;
      top: 14px;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 8px;
      min-width: 80px;

      .btn-switch-direction {
        background: #4299e1;
        color: white;
        border: none;
        border-radius: 50%;
        width: 40px;
        height: 40px;
        cursor: pointer;
        font-size: 18px;
        display: flex;
        align-items: center;
        justify-content: center;
        transition: all 0.2s ease;
        box-shadow: 0 2px 6px rgba(66, 153, 225, 0.3);
      }

      .btn-switch-direction:hover {
        background: #3182ce;
        transform: translateY(-2px);
        box-shadow: 0 4px 12px rgba(66, 153, 225, 0.4);
      }
    }
  }
}
</style>
